package hosts

import (
	"bufio"
	"bytes"
	"fmt"
	"github.com/sirupsen/logrus"
	"io"
	"net"
	"net/http"
	"os"
	"proxy/common"
	"regexp"
	"strconv"
	"strings"
	"time"
)

type status string

const (
	UP   status = "UP"
	Down        = "Down"
)

type service struct {
	IP     string
	Port   int
	Status status
}

func (s *service) IsRun() bool { //判断服务是否运行。
	_, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", s.IP, s.Port), time.Duration(1)*time.Second)
	if err != nil {
		logrus.Errorf("checkWeb err:%s\n", err)
		return false
	} else {
		return true
	}
}

func (s *service) IsValid() bool { //判断服务是否可用。

	Url := s.URL() + "/show/integrate"

	// 要发送的数据
	jsonData := []byte(`{"way": "630-1"}`)

	// 创建一个请求
	req, err := http.NewRequest("POST", Url, bytes.NewBuffer(jsonData))
	if err != nil {
		logrus.Error(err)
		return false
	}

	// 设置请求头，例如设置Content-Type为表单数据
	req.Header.Set("Content-Type", "application/json")

	// 发送请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		logrus.Error(err)
		return false
	}
	defer resp.Body.Close()

	// 读取响应内容
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		logrus.Fatal(err)
	}
	//body := []byte(`{"msg":"操作成功","code":200,"data":{"time_long":1735569695880,"remark":"","ret_code":0,"time_str":"2024-12-30 22:41:35.880"}}`)
	pattern := `请求过于频繁|操作成功`

	// 编译正则表达式
	re, err := regexp.Compile(pattern)
	if err != nil {
		logrus.Error("Error compiling regex:", err)
		return false
	}

	isOK := re.MatchString(string(body))
	return isOK
}

func (s *service) URL() string {
	return fmt.Sprintf("http://%s:%d", s.IP, s.Port)
}

type SignalUpdateObject struct { //构造消息通信的双向通道。更新时构建此类型数据 给Engine，Engine的返回值通过Response 返回給调用者。
	IP       string
	Req      string
	Response chan string
}

type SignalProxyObject struct {
	Response chan string
}

var ChanOfUpdate chan SignalUpdateObject
var ChanOfLoadBalance chan SignalProxyObject

func healthCheck(hostsMap map[string]*service) {
	for _, h := range hostsMap {
		if ok := h.IsRun(); ok {
			h.Status = UP
		} else {
			h.Status = Down
		}
	}
	logrus.Info("健康检查的结果是：")
	Print(hostsMap)
}

func loadHosts() (mH map[string]*service, IPs []string) { //从配置文件中获取后端服务信息。
	mH = make(map[string]*service)
	configFilename := common.GetConfigFile()
	//fmt.Println("configFilename is ", configFilename)
	file, err := os.Open(configFilename)
	if err != nil {
		fmt.Printf("读取配置文件%s失败！\n", configFilename)
		logrus.Fatal(err)
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		str := scanner.Text()

		if str != "" {
			split := strings.Split(str, ":")
			port, err := strconv.Atoi(split[1])
			if err != nil {
				logrus.Fatal(err)
			}
			ip := split[0]
			mH[ip] = &service{Status: UP, IP: ip, Port: port}
			IPs = append(IPs, ip)
		}
	}
	return
}

var (
	hostsMap map[string]*service
	IPs      []string
	position = 0
)

func runEngine() {
	ChanOfUpdate = make(chan SignalUpdateObject)     //接收讯号的channel，用来告诉代理服务，后端一个服务要更新了
	ChanOfLoadBalance = make(chan SignalProxyObject) //接收讯号的channel，用来获取后端众多服务中的一个的
	go func() {
		t := time.Tick(5 * time.Second)
		for {
			select {
			case <-t:
				healthCheck(hostsMap)
			case u := <-ChanOfUpdate:
				update(u, hostsMap)
			case l := <-ChanOfLoadBalance:
				loadBalance(l)
			}
		}
	}()
}

func Loading() {
	hostsMap, IPs = loadHosts()
	//Print(hostsMap)
	runEngine()
}

func Print(m map[string]*service) {
	for _, h := range m {
		s := fmt.Sprintf("%s:%d %s", h.IP, h.Port, h.Status)
		common.BluePrintln(s)
	}
}

func update(s SignalUpdateObject, mHosts map[string]*service) {
	if _, ok := mHosts[s.IP]; !ok {
		logrus.Errorf("Invalid ip %s", s.IP)
		s.Response <- "no"
		return
	}

	switch s.Req {
	case "/U":
		fmt.Printf("%s申请更新\n", s.IP)
		status := mHosts[s.IP].Status
		num := 0
		if status == Down { //提出更新请求时，但本身已经处在下线状态，同意更新。
			s.Response <- "yes"
			str := fmt.Sprintf("%s的更新申请被允许！num=%d", s.IP, num)
			common.GreenPrintln(str)
		} else {
			for _, h := range mHosts {
				if h.Status == UP {
					num++
				}
			}

			if num-1 > 0 { //更新时至少有一个主机可以对外提供服务，同意更新。
				mHosts[s.IP].Status = Down
				s.Response <- "yes"
				str := fmt.Sprintf("%s的更新申请被允许！num=%d", s.IP, num)
				common.GreenPrintln(str)
				num--
			} else { //只剩最后一个主机可以对外提供服务，所以更新请求被否决
				s.Response <- "no"
				str := fmt.Sprintf("%s的更新申请被拒绝！", s.IP)
				common.RedPrintln(str)
			}
		}
	case "/D":
		mHosts[s.IP].Status = UP
		s.Response <- "yes"
		fmt.Printf("%s已更新完成！\n", s.IP)
	}
}

func loadBalance(s SignalProxyObject) {
	//fmt.Println("position is", position)
	for {
		if position >= len(IPs) {
			position = 0
		}
		//log.Printf("The position %d\n",position)
		ip := IPs[position]
		position++

		h, ok := hostsMap[ip]
		if !ok {
			logrus.Fatalf("Invalid ip %s", ip)
		}

		if h.Status == UP && h.IsRun() {
			s.Response <- h.URL()
			break
		}
	}
}
